#include <stdio.h>
#include <stdlib.h>
#include "SList.h"
#include <assert.h>

/* 新节点的申请 */
SLTNode* SLT_Buynode(SLTdatatype x)
{
    SLTNode *newnode = (SLTNode *)malloc(sizeof(SLTNode));
    // 代码健康度更高
    if (newnode == NULL)
    {
        perror("malloc error");
        exit(1);
    }
    newnode->data = x;
    newnode->next = NULL;
    return newnode;
}



/* 打印链表 */
/* 输入参数为头指针 */
void SLT_Print(SLTNode *phead)
{
    SLTNode *Pchar = phead;
    while (Pchar != NULL)
    {
        printf("%d->", Pchar->data);
        Pchar = Pchar->next;
    }
    printf("NULL\n");
}
// 1 -> NULL

/* 尾插链表 */
/* 我们需要改动真实的指针地址 需要的是头指针 的地址 需要加& */
/* 需要二级指针是因为传入的那个指针的地址是复制品 后面的不是 而如果要改动传入的那个指针 就必须使用二级指针了*/
/* **pphead是指向第一个指针的指针 */
void SLT_Pushback(SLTNode **pphead, SLTdatatype x)
{
    assert(pphead);
    SLTNode *newnode = SLT_Buynode(x);
    // 链表为空, 新节点作为phead
    if (*pphead == NULL)
    {
        *pphead = newnode;
        return;
    }
    // 链表不为空, 找尾节点
    SLTNode *Ptail = *pphead;
    while (Ptail->next != NULL)
    {
        Ptail = Ptail->next;
    }
    // ptail就是尾节点
    Ptail->next = newnode;
} 

/* 头插 */
void SLT_Pushfront(SLTNode **pphead, SLTdatatype x)
{
    assert(pphead);
    SLTNode *newnode = SLT_Buynode(x);
    
    newnode->next = *pphead;
    *pphead = newnode;
}

/* 尾删 */
void SLT_Popback(SLTNode **pphead)
{
    assert(pphead);
    // 链表不能为空
    assert(*pphead);
    //链表不为空 
    //只有一个节点
    if ((*pphead)->next == NULL)
    {
        free(*pphead);
        *pphead = NULL;
        return;
    }
    //有多个节点
    SLTNode *ptail = *pphead;
    SLTNode *pprev = NULL;
    while (ptail->next != NULL)
    {
        pprev = ptail;
        ptail = ptail->next;
    }
    // 释放尾节点
    free(ptail);
    // 尾节点前的指针置空
    pprev->next = NULL;
}


/* 头删 */
void SLT_Popfront(SLTNode **pphead)
{
    // 指针不为空
    assert(*pphead);
    // 需要free第一个头 方法如下 
    // 1. 定义临时指针保存头节点
    // 2. 临时指针保存第二个节点
    SLTNode *pold = *pphead;

    *pphead = (*pphead)->next;
    free(*pphead);
}


// 查找 返回地址
SLTNode *SLT_Find(SLTNode **pphead, SLTdatatype x)
{
    // 头不为空
    assert(pphead);
    assert(*pphead);

    SLTNode *pcur = *pphead;
    while (pcur != NULL)
    {
        if (pcur->data == x)
        {
            return pcur;
        }
        pcur = pcur->next;
    }
    // 找不到
    return NULL;
}


// 指定位置之前
// 寻找前置节点
void SLT_Insert(SLTNode **pphead, SLTdatatype x, SLTNode *pos)
{
    assert(pphead);
    assert(pos);
    // 加上链表不能为空 链表如果也为空的话pos也为空了呀 而且根本找不到前驱节点
    assert(*pphead);

    // 申请空间
    SLTNode *newnode = SLT_Buynode(x);

    // pos 是头节点
    if (pos == *pphead)
    {
        newnode->next = pos;
        *pphead = newnode;
        return;
    }

    // pos不是头节点
    // 找到前驱节点
    SLTNode *prev = *pphead;
    while (prev->next != pos)
    {
        prev = prev->next;
    }

    prev->next = newnode;
    newnode->next = pos;
}




// 指定位置之后
// 已经知道地址了
void SLT_InsertAfter(SLTdatatype x, SLTNode *pos)
{
    assert(pos);

    // 申请新指针    
    SLTNode *newnode = SLT_Buynode(x);

    // 插入
    newnode->next = pos->next;
    pos->next = newnode;
}



// 删除指定位置节点
void SLT_Erase(SLTNode **pphead, SLTNode *pos)
{
    assert(pphead);
    assert(pos);
    assert(*pphead);

    SLTNode *prev = *pphead;

    // pos 刚好是头节点
    if (pos == *pphead)
    {
        SLT_Popfront(pphead);
        return;        
    }
    
    // 寻找前驱节点
    while (prev->next != pos)
    {
        prev = prev->next;
    }

    prev->next = pos->next;

    free(pos);
    pos = NULL;
}


// 删除指定位置以后节点
void SLT_EraseAfter(SLTNode **pphead, SLTNode *pos)
{
    assert(pos);

    // pos的后继节点不能为空
    assert(pos->next);

    SLTNode *ptmp = pos->next;
    pos->next = pos->next->next;
    free(ptmp);
    ptmp = NULL;
}


// 销毁链表
void SLT_Destory(SLTNode **pphead)
{
    assert(pphead);
    assert(*pphead);

    SLTNode *pcur = *pphead;

    while (pcur != NULL)
    {
        // 保存后置节点 以便寻找
        SLTNode *pnext = pcur->next;    
        free(pcur);
        pcur = pnext;
    }
    *pphead = NULL;
}